using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using Peak.Can.Basic;
using System.Security.Cryptography;

namespace WinCANTool
{


    public partial class FlashWindow1319 : Form
    {
        private byte[] Fragment;
        //private byte[][] SegData;
        
        private const int FLASH_DATA_DLY = 1;
        private const int FLASH_CMD_DLY = 10;
        
        public bool debug_flash = true;
        public const int FULL_FILE_SIZE = 10000000;
        public const uint WAIT_TIME = 0x7fffffff;
        public const int KWP_SEND_ALL = 0x780;
        public uint TxNodeId=0x783;
        public uint RxNodeId=0x793;
        //public int[] FileSize;
        public int BLOCK_SIZE;
        public int ReturnValue = 0;
        public int data_download = 0;

        uint ReadCount = 0;
        private TPCANMsg CanMessageOut = new TPCANMsg();
        private TPCANMsg CanMessageIn = new TPCANMsg();
        private Queue<TPCANMsg> MsgQueue = new Queue<TPCANMsg>(1);
        public string FileInName;
        public int NodeId;
        public int FlashKeyIn;
        public int CommandObjectIndex;
        public int FileObjectIndex;
        public int SDODataValue;
        public int FullBlockCount;
        public int init_value = 0xff;
        public          int tx_index;

        //public int[] flashAddr;

        public byte ClientCommandSpecifier;
        private NewMessage MessageToSend = new NewMessage();
        public bool FlashOpOn = false;
        public bool SegmentWrite = false;
        public bool SegmentTransferON = false;
        public bool ValueWrite = false;
        public bool FileOpen = false;
        public bool MessageOk = false;
        public bool CTFTest1 = false;
        public bool CTFTest2 = false;
        public bool SendValue = false;
        public bool LastValue = false;
        public bool SendMessageON = false;
        public bool SetLastValue = false;
        public bool UseSecondChannel = false;
        private EventArgs Args = new EventArgs();
        //public event EventHandler FlashDone;
        public event EventHandler TickDone;
        public event EventHandler KwpDone;
        public delegate void MessageOpHandler(object CurrentForm, MessageOpArgs ReturnResult);
        public event MessageOpHandler MessageOpDone;
        public event MessageOpHandler FlashOpDone;
        public MessageOpArgs OpArgs = new MessageOpArgs();
        public  string path_cur = System.IO.Directory.GetCurrentDirectory();  
        public string hardware_id;
        public string part_number;
        public int software_ver;
        public string software_id;
        public string serial_number;
        public string security_key;
        public string mac_address;
        public uint secacc_crypto_12( uint seed )
        {
           /* calculate key */
           const uint a = 0x974c58ab;
           const uint b = 0xfedcba98;
           const uint c = 0x98765432;
           uint x = seed + a;

           if( (0xffffffff - a) < seed)
           {
              x ^= b;
           }
           else
           {
              x ^= c;
           }

           x = (x >> 11) | ((x & 0x7ff) << 21);

           return x;
        }

        public uint secacc_crypto_34( uint seed )
        {
           return seed + 0x1AF7;
        }

        

        public void start_diagnostic()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x10;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x81;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x50)
                ReturnValue = 0;
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        
        }

        public void read_hw_id()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x1A;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x80;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x5A)
            {
                ReturnValue = 0;
                int id = Convert.ToInt32(CanMessageIn.DATA[2]); 
                hardware_id =  Convert.ToString(id); 
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        
        }


        public void read_partnumber()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x21;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x00;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x61 || CanMessageIn.DATA[1] == 0x7f)
            {
                ReturnValue = 0;

                if(CanMessageIn.DATA[1] == 0x61)
                {
                    byte []data = new byte[4] {CanMessageIn.DATA[3],CanMessageIn.DATA[4],CanMessageIn.DATA[5],CanMessageIn.DATA[6]}; 
                    int number = BitConverter.ToInt32(data,0);
                    part_number =  Convert.ToString(number);
                }
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        
        }


        public void verify_partnumber()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x21;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x00;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x61 || CanMessageIn.DATA[1] == 0x7f)
            {
                ReturnValue = 0;
                if(CanMessageIn.DATA[1] == 0x61)
                {
                    byte []data = new byte[4] {CanMessageIn.DATA[3],CanMessageIn.DATA[4],CanMessageIn.DATA[5],CanMessageIn.DATA[6]}; 
                    int number = BitConverter.ToInt32(data,0);
                    part_number =  Convert.ToString(number);

                    if(part_number != "1155400712")
                    {
                        ReturnValue = -99;
                        OpArgs.ReturnOpValue = ReturnValue;
                        SendMessageEndEvent(OpArgs);
                    }
                }
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        
        }   
        

        public void read_brandid()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x21;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x03;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x61 || CanMessageIn.DATA[1] == 0x7f)
            {
                ReturnValue = 0;
                if(CanMessageIn.DATA[1] == 0x61)
                {
                    int part_num = Convert.ToInt32(CanMessageIn.DATA[2]);   
                    part_number =  Convert.ToString(part_num); 
                }
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        
        }   

        public void verify_brandid()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x21;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x03;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x61 || CanMessageIn.DATA[1] == 0x7f)
            {
                ReturnValue = 0;
                if(CanMessageIn.DATA[1] == 0x61)
                {
                    byte []data = new byte[2] {CanMessageIn.DATA[3],CanMessageIn.DATA[4]}; 
                    int brand_id = BitConverter.ToInt16(data,0);

                    if (brand_id != 0x0100)
                    {
                        ReturnValue = -99;
                        OpArgs.ReturnOpValue = ReturnValue;
                        SendMessageEndEvent(OpArgs);        
                    }
                }
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        
        }           


        public void read_ID36()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x21;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x36;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x61 || CanMessageIn.DATA[1] == 0x7f)
            {
                ReturnValue = 0;
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        
        }   

        public void verify_ID36()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x21;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x36;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x61 || CanMessageIn.DATA[1] == 0x7f)
            {
                ReturnValue = 0;
                byte []data = new byte[2] {CanMessageIn.DATA[3],CanMessageIn.DATA[4]}; 
                int id_36 = BitConverter.ToInt16(data,0);

                if(id_36 != 0x0B86)
                {
                    ReturnValue = -99;
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);        
                }

                
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        
        }   

        
        public void read_ID20()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x21;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x20;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x61 || CanMessageIn.DATA[1] == 0x7f)
            {
                ReturnValue = 0;
                byte []data = new byte[2] {CanMessageIn.DATA[3],CanMessageIn.DATA[4]}; 
                int id_20 = BitConverter.ToInt32(data,0);

                if(id_20 != 0x0001)
                {
                    ReturnValue = -99;
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);        
                }
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        
        }

        public void verify_ID20()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x21;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x20;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x61 || CanMessageIn.DATA[1] == 0x7f)
            {
                byte []data = new byte[2] {CanMessageIn.DATA[3],CanMessageIn.DATA[4]}; 
                int id_20 = BitConverter.ToInt16(data,0);

                if(id_20 != 0x0001)
                {
                    ReturnValue = -99;
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);        
                }
				
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        
        }
        
        

        public void read_IDC0()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x21;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0xC0;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x61 || CanMessageIn.DATA[1] == 0x7f)
            {
                ReturnValue = 0;
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        
        }

        public void verify_IDC0()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x21;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0xC0;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x61 || CanMessageIn.DATA[1] == 0x7f)
            {
                ReturnValue = 0;
                if(CanMessageIn.DATA[1] == 0x61)
                {
                    byte []data = new byte[2] {CanMessageIn.DATA[3],CanMessageIn.DATA[4]}; 
                    int id_c0 = BitConverter.ToInt16(data,0);

                    if(id_c0 != 0x0001)
                    {
                        ReturnValue = -99;
                        OpArgs.ReturnOpValue = ReturnValue;
                        SendMessageEndEvent(OpArgs);        
                    }
                }
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        
        }
        

        public void read_ecu_variant()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x21;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x80;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x61 || CanMessageIn.DATA[1] == 0x7f)
            {
                ReturnValue = 0;
                if(CanMessageIn.DATA[1] == 0x61)
                {
                    int part_num = Convert.ToInt32(CanMessageIn.DATA[2]);   
                    part_number =  Convert.ToString(part_num); 
                }
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        
        }           

        public void verify_ecu_variant()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x21;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x80;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x61 || CanMessageIn.DATA[1] == 0x7f)
            {
                ReturnValue = 0;
                if(CanMessageIn.DATA[1] == 0x61)
                {
                    byte []data = new byte[2] {CanMessageIn.DATA[3],CanMessageIn.DATA[4]}; 
                    int ecu_variant = BitConverter.ToInt16(data,0);

                    if(ecu_variant != 0x0019)
                    {
                        ReturnValue = -99;
                        OpArgs.ReturnOpValue = ReturnValue;
                        SendMessageEndEvent(OpArgs);        
                    }
                }
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        
        }       

        public void read_swid()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x1A;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x81;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[2] == 0x5A || CanMessageIn.DATA[1] == 0x7f)
            {
                ReturnValue = 0;
                if(CanMessageIn.DATA[2] == 0x5A)
                    software_id = Convert.ToString(CanMessageIn.DATA[3]);
                else
                    return;
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
            Thread.Sleep(FLASH_CMD_DLY);
            

            CanMessageOut.DATA[0] = 0x30;       //  start default session
            CanMessageOut.DATA[1] = 00; //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x0A;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
        
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);

            if (CanMessageIn.DATA[0] == 0x21)
            {
                ReturnValue = 0;
                software_id += Convert.ToString(CanMessageIn.DATA[1]);
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        }   

        public void read_swid2()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x1A;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x82;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[2] == 0x5A || CanMessageIn.DATA[1] == 0x7f)
            {
                ReturnValue = 0;
                if(CanMessageIn.DATA[2] == 0x5A)
                    software_id = Convert.ToString(CanMessageIn.DATA[3]);
                else
                    return;
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
            Thread.Sleep(FLASH_CMD_DLY);
            

            CanMessageOut.DATA[0] = 0x30;       //  start default session
            CanMessageOut.DATA[1] = 00; //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x0A;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
        
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);

            if (CanMessageIn.DATA[0] == 0x21)
            {
                ReturnValue = 0;
                software_id += Convert.ToString(CanMessageIn.DATA[1]);
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        }           

        public void read_swid3()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x1A;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x83;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[2] == 0x5A || CanMessageIn.DATA[1] == 0x7f)
            {
                ReturnValue = 0;
                if(CanMessageIn.DATA[2] == 0x5A)
                    software_id = Convert.ToString(CanMessageIn.DATA[3]);
                else
                    return;
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
            Thread.Sleep(FLASH_CMD_DLY);
            

            CanMessageOut.DATA[0] = 0x30;       //  start default session
            CanMessageOut.DATA[1] = 00; //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x0A;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
        
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);

            if (CanMessageIn.DATA[0] == 0x21)
            {
                ReturnValue = 0;
                software_id += Convert.ToString(CanMessageIn.DATA[1]);
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        }


        public void read_software_version()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x1A;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x84;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x5A || CanMessageIn.DATA[1] == 0x7F)
            {
                ReturnValue = 0;
                if(CanMessageIn.DATA[1] == 0x5A)
                {
                    software_ver = Convert.ToInt16(CanMessageIn.DATA[2]);
                }
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        
        }       
        

        public void stop_diagnostic()
        {
            CanMessageOut.DATA[0] = 1;      //  start default session
            CanMessageOut.DATA[1] = 0x20;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0xff;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x60)
                ReturnValue = 0;
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        
        }

        public void seacc_ff()
        {
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x27;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0xff;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x7f)
                ReturnValue = 0;
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
        
        }       
        

        public void start_programming()
        {
            CanMessageOut.ID = KWP_SEND_ALL;
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x10;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x85;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x50)
                ReturnValue = 0;
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
            CanMessageOut.ID = TxNodeId;
        
        }

        public void write_param(byte id, byte[] value, byte length)
        {           
            CanMessageOut.DATA[0] = length;     //  security 3/4
            CanMessageOut.DATA[1] = 0x3B;   //  
            CanMessageOut.DATA[2] = id;

            for(int i = 3; i < 8; i++)
            {
                CanMessageOut.DATA[i] = 0xff; 
            }           

            for(int i = 0; i < length-2; i++)
            {
                CanMessageOut.DATA[3+i] = value[i];
            }
            
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);
            MessageOk = false;
            ReadCount = WAIT_TIME;
            CanMessageIn.DATA[1] = 0x00;
            ReturnValue = 0; 

            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    //SendMessageEndEvent(OpArgs);
                    return;
                }   
                if(MessageOk == true)
                    {
                    ReadCount = WAIT_TIME/4;
                    }
            } while ((CanMessageIn.DATA[1] != 0x7B) && (CanMessageIn.DATA[3] != 0x12));
            
            if (CanMessageIn.DATA[1] == 0x7B || CanMessageIn.DATA[1] == 0x7F)
            {
                ReturnValue = 0;
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }   
            
        }
        
        

        public void secacc_process_34()
        {
            uint sec_seed;
            uint sec_key;
            byte[] temp_data;
            CanMessageOut.DATA[0] = 2;      //  security 3/4
            CanMessageOut.DATA[1] = 0x27;   //  
            CanMessageOut.DATA[2] = 0x03;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x67)
            {
                ReturnValue = 0;
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }   
            
            sec_seed = CanMessageIn.DATA[3];
            sec_seed |= ((uint)CanMessageIn.DATA[4]) << 8;
            sec_seed |= ((uint)CanMessageIn.DATA[5]) << 16;
            sec_seed |= ((uint)CanMessageIn.DATA[6]) << 24;
            sec_key = secacc_crypto_34(sec_seed);

            temp_data = BitConverter.GetBytes(sec_key);
            Thread.Sleep(FLASH_CMD_DLY);

            CanMessageOut.DATA[0] = 6;      //  start default session
            CanMessageOut.DATA[1] = 0x27;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x04;
            CanMessageOut.DATA[3] = temp_data[0];
            CanMessageOut.DATA[4] = temp_data[1];
            CanMessageOut.DATA[5] = temp_data[2];
            CanMessageOut.DATA[6] = temp_data[3];
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
        
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x67)
                ReturnValue = 0;
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }   
        }


        public void secacc_process_56()
        {
            uint sec_seed;
            uint sec_key;
            byte[] temp_data;
            CanMessageOut.DATA[0] = 2;      //  security 5/6
            CanMessageOut.DATA[1] = 0x27;   //  
            CanMessageOut.DATA[2] = 0x05;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x67)
            {
                ReturnValue = 0;
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
            Thread.Sleep(FLASH_CMD_DLY);
            
            sec_seed = CanMessageIn.DATA[3];
            sec_seed |= ((uint)CanMessageIn.DATA[4]) << 8;
            sec_seed |= ((uint)CanMessageIn.DATA[5]) << 16;
            sec_seed |= ((uint)CanMessageIn.DATA[6]) << 24;
            sec_key = secacc_crypto_56(sec_seed);

            temp_data = BitConverter.GetBytes(sec_key);         

            CanMessageOut.DATA[0] = 6;      //  start default session
            CanMessageOut.DATA[1] = 0x27;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x06;
            CanMessageOut.DATA[3] = temp_data[0];
            CanMessageOut.DATA[4] = temp_data[1];
            CanMessageOut.DATA[5] = temp_data[2];
            CanMessageOut.DATA[6] = temp_data[3];
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
        
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x67)
                ReturnValue = 0;
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }   
        }
        

        public void enter_passive_mode()
        {
            CanMessageOut.ID = KWP_SEND_ALL;

            CanMessageOut.DATA[0] = 3;      //  enter passive mode
            CanMessageOut.DATA[1] = 0x31;   //  
            CanMessageOut.DATA[2] = 0x04;
            CanMessageOut.DATA[3] = 0;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x71)
                ReturnValue = 0;
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }   
            CanMessageOut.ID = TxNodeId;
        }

        public void flash_data(int seg_no)
        {
            int BytesRead, BlockCtr = 0;
            byte[] block_full_byte;
            int block_cnt_full;
            int block_left_bytes;
            int blockIndex = 0;
            //int block_cnt;
            int remain_cnt;
            byte segIndex;
            int seg_cnt;
            byte[] temp_data;

            temp_data = new byte[8];
            block_full_byte = new byte[2];
            Thread.Sleep(FLASH_CMD_DLY);
            request_download(seg_no);
            Thread.Sleep(FLASH_CMD_DLY);
            delete_flash(seg_no);
            Thread.Sleep(FLASH_CMD_DLY);
            data_download = 1;
            BlockCtr = FileSize[seg_no] / BLOCK_SIZE;
            if(FileSize[seg_no] % BLOCK_SIZE != 0)
            {
                BlockCtr++;
            }               
  
            FullBlockCount  = BlockCtr;

            block_cnt_full = (BLOCK_SIZE - 5)/7; // first block will be five

            block_left_bytes = (BLOCK_SIZE - 5)%7;

            tx_index = 0;

            init_value = 0;


            block_full_byte = BitConverter.GetBytes(BLOCK_SIZE + 1);

            blockIndex = 0;
            while (BlockCtr - 1 > 0)        // handle full(whole) blocks first            
            {
                CanMessageOut.DATA[0] = 0x10;
                CanMessageOut.DATA[0] += block_full_byte[1];    //  Sequence Counter
                CanMessageOut.DATA[1] = block_full_byte[0]; //  7 bytes of Data
                CanMessageOut.DATA[2] = 0x36;
                CanMessageOut.DATA[3] = SegData[seg_no][tx_index++];
                CanMessageOut.DATA[4] = SegData[seg_no][tx_index++];
                CanMessageOut.DATA[5] = SegData[seg_no][tx_index++];
                CanMessageOut.DATA[6] = SegData[seg_no][tx_index++];
                CanMessageOut.DATA[7] = SegData[seg_no][tx_index++];

                MessageToSend.ConvertNewMessage(CanMessageOut);
                SendFlashMessage(MessageToSend);
                Thread.Sleep(FLASH_CMD_DLY);


                MessageOk = false;
                if(debug_flash)
                {
                    ReadCount = WAIT_TIME;
                }
                else
                {
                    ReadCount = WAIT_TIME;
                }
            
                do
                {
                    MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                    if (ReadCount-- == 0)
                    {
                        if(debug_flash)
                        {
                            break;
                        }
                        OpArgs.ReturnOpValue = ReturnValue;
                        SendMessageEndEvent(OpArgs);
                    }

                } while (MessageOk == false);
                
                if (CanMessageIn.DATA[1] == 0x00 || debug_flash)
                    ReturnValue = 0;
                else
                {
                    ReturnValue = -99;
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }


                for(segIndex = 0; segIndex < block_cnt_full; segIndex++)
                {
                    CanMessageOut.DATA[0] = 0x20;
                    temp_data = BitConverter.GetBytes((segIndex + 1) % 16); //  Sequence Counter
                    CanMessageOut.DATA[0] += temp_data[0]; 
                    
                    CanMessageOut.DATA[1] = SegData[seg_no][tx_index++];    //  7 bytes of Data
                    CanMessageOut.DATA[2] = SegData[seg_no][tx_index++];
                    CanMessageOut.DATA[3] = SegData[seg_no][tx_index++];
                    CanMessageOut.DATA[4] = SegData[seg_no][tx_index++];
                    CanMessageOut.DATA[5] = SegData[seg_no][tx_index++];
                    CanMessageOut.DATA[6] = SegData[seg_no][tx_index++];
                    CanMessageOut.DATA[7] = SegData[seg_no][tx_index++];
                    MessageToSend.ConvertNewMessage(CanMessageOut);
                    SendFlashMessage(MessageToSend);
                    Thread.Sleep(FLASH_DATA_DLY);

                }

                if(block_left_bytes > 0)
                {
                    remain_cnt = block_left_bytes;

                    temp_data = BitConverter.GetBytes((block_cnt_full + 1) % 16);   //  Sequence Counter
                    CanMessageOut.DATA[0] = 0x20;

                    CanMessageOut.DATA[0] += temp_data[0];  //  Sequence Counter


                    for(int k = 1; k < remain_cnt + 1; k++)  // 256 - 5 - 35*7=
                    {
                        CanMessageOut.DATA[k] = SegData[seg_no][tx_index++];    //  7 bytes of Data
                    }
                    MessageToSend.ConvertNewMessage(CanMessageOut);
                    SendFlashMessage(MessageToSend);
                    Thread.Sleep(FLASH_DATA_DLY);


                    MessageOk = false;
                    if(debug_flash)
                    {
                        ReadCount = WAIT_TIME;
                    }
                    else
                    {
                        ReadCount = WAIT_TIME;
                    }               
                    do
                    {
                        MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                        if (ReadCount-- == 0)
                        {
                            if(debug_flash)
                            {
                                break;
                            }
                            OpArgs.ReturnOpValue = ReturnValue;
                            SendMessageEndEvent(OpArgs);
                        }

                    } while (MessageOk == false);
                    
                    if (CanMessageIn.DATA[1] == 0x76 || debug_flash)
                        ReturnValue = 0;
                    else
                    {
                        ReturnValue = -99;
                        OpArgs.ReturnOpValue = ReturnValue;
                        SendMessageEndEvent(OpArgs);
                    }
                }

                SendTickEvent(Args);
                BlockCtr--;                             // remaining number of blocks
                blockIndex++;
                if(FullBlockCount / 2 == blockIndex)
                {
                    Thread.Sleep(FLASH_CMD_DLY);
                }
                else
                {
                    Thread.Sleep(FLASH_CMD_DLY);
                }
            }           // all full blocks sent
            BytesRead = FileSize[seg_no] - blockIndex * BLOCK_SIZE;
            if(BytesRead != 0)
            {
                temp_data = BitConverter.GetBytes(BytesRead + 1);

                CanMessageOut.DATA[0] = 0x10;   //  Sequence Counter
                CanMessageOut.DATA[0] += temp_data[1];  //  Sequence Counter
                CanMessageOut.DATA[1] = temp_data[0];   //  7 bytes of Data
                CanMessageOut.DATA[2] = 0x36;


                CanMessageOut.DATA[3] = SegData[seg_no][tx_index++];
                CanMessageOut.DATA[4] = SegData[seg_no][tx_index++];
                CanMessageOut.DATA[5] = SegData[seg_no][tx_index++];
                CanMessageOut.DATA[6] = SegData[seg_no][tx_index++];
                CanMessageOut.DATA[7] = SegData[seg_no][tx_index++];

                MessageToSend.ConvertNewMessage(CanMessageOut);
                SendFlashMessage(MessageToSend);
                Thread.Sleep(FLASH_CMD_DLY);
                

                MessageOk = false;
                if(debug_flash)
                {
                    ReadCount = WAIT_TIME;
                }
                else
                {
                    ReadCount = WAIT_TIME;
                }
                do
                {
                    MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                    if (ReadCount-- == 0)
                    {
                        if(debug_flash)
                        {
                            break;
                        }
                        OpArgs.ReturnOpValue = ReturnValue;
                        SendMessageEndEvent(OpArgs);
                    }

                } while (MessageOk == false);

                if (CanMessageIn.DATA[1] == 0x00 || debug_flash)
                {
                    ReturnValue = 0;
                }
                else
                {
                    ReturnValue = -99;
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }


                seg_cnt = (BytesRead - 5) / 7;

                for (int j = 0; j < seg_cnt; j++)                   // send remaining full sequence fragments
                {
                    CanMessageOut.DATA[0] = 0x20;   //  Sequence Counter

                    temp_data = BitConverter.GetBytes((j + 1) % 16);

                    CanMessageOut.DATA[0] += temp_data[0];  //  Sequence Counter
                    for ( int k = 1; k < 8; k++)
                    {
                        CanMessageOut.DATA[k] = SegData[seg_no][tx_index++];    //  7 bytes of Data (some of these might be DNC as this is the last block?
                    }

                    MessageToSend.ConvertNewMessage(CanMessageOut);
                    SendFlashMessage(MessageToSend);
                    Thread.Sleep(FLASH_DATA_DLY);
                }


                BytesRead = (BytesRead - 5) % 7;


                if(BytesRead != 0)
                {
                    CanMessageOut.DATA[0] = 0x20;   //  Sequence Counter
                    temp_data = BitConverter.GetBytes((seg_cnt + 1) % 16);
                    CanMessageOut.DATA[0] += temp_data[0];  //  Sequence Counter
                    for (int  k = 1; k < BytesRead + 1; k++)
                    {
                        CanMessageOut.DATA[k] = SegData[seg_no][tx_index++];    //  7 bytes of Data (some of these might be DNC as this is the last block?
                    }

                    MessageToSend.ConvertNewMessage(CanMessageOut);
                    SendFlashMessage(MessageToSend);
                    Thread.Sleep(FLASH_DATA_DLY);

                    MessageOk = false;
                    if(debug_flash)
                    {
                        ReadCount = WAIT_TIME;
                    }
                    else
                    {
                        ReadCount = WAIT_TIME;
                    }       
                    do
                    {
                        //Thread.Sleep(1);
                        MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                        if (ReadCount-- == 0)
                        {
                            //SendFlashEndEvent(Args);
                            if(debug_flash)
                            {
                                break;
                            }
                            OpArgs.ReturnOpValue = ReturnValue;
                            SendMessageEndEvent(OpArgs);
                        }

                    } while (MessageOk == false);

                    if (CanMessageIn.DATA[1] == 0x76 || debug_flash)
                    {
                        ReturnValue = 0;
                    }
                    else
                    {
                        ReturnValue = -99;
                        OpArgs.ReturnOpValue = ReturnValue;
                        SendMessageEndEvent(OpArgs);
                    }
                    
                }
                SendTickEvent(Args);
                
            }
            data_download = 0;
            Thread.Sleep(FLASH_CMD_DLY);
            
            request_transfer_exit(seg_no);
            Thread.Sleep(FLASH_CMD_DLY);
            
            calculate_checksum(seg_no);
            Thread.Sleep(FLASH_CMD_DLY);
            Thread.Sleep(1000);
        
        }

        public void start_flasher()
        {
            CanMessageOut.ID = KWP_SEND_ALL;

            CanMessageOut.DATA[0] = 3;      //  start flasher
            CanMessageOut.DATA[1] = 0x31;   //  
            CanMessageOut.DATA[2] = 0x01;
            CanMessageOut.DATA[3] = 0x00;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x71)
                ReturnValue = 0;
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }   
            CanMessageOut.ID = TxNodeId;
        }

        public void secacc_process_12()
        {
            uint sec_seed;
            uint sec_key;
            byte[] temp_data;
            CanMessageOut.DATA[0] = 2;      //  requeset seed1/2
            CanMessageOut.DATA[1] = 0x27;   //  
            CanMessageOut.DATA[2] = 0x01;
            CanMessageOut.DATA[3] = 0x00;
            CanMessageOut.DATA[4] = 0x00;
            CanMessageOut.DATA[5] = 0x00;
            CanMessageOut.DATA[6] = 0x00;
            CanMessageOut.DATA[7] = 0x00;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x67)
                ReturnValue = 0;
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }   
            Thread.Sleep(FLASH_CMD_DLY);

            sec_seed = CanMessageIn.DATA[3];
            sec_seed |= ((uint)CanMessageIn.DATA[4]) << 8;
            sec_seed |= ((uint)CanMessageIn.DATA[5]) << 16;
            sec_seed |= ((uint)CanMessageIn.DATA[6]) << 24;

            sec_key = secacc_crypto_12(sec_seed);


            temp_data = BitConverter.GetBytes(sec_key);         

            CanMessageOut.DATA[0] = 6;      //  start default session
            CanMessageOut.DATA[1] = 0x27;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x02;
            CanMessageOut.DATA[3] = temp_data[0];
            CanMessageOut.DATA[4] = temp_data[1];
            CanMessageOut.DATA[5] = temp_data[2];
            CanMessageOut.DATA[6] = temp_data[3];
            CanMessageOut.DATA[7] = 0x00;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
        
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x67)
                ReturnValue = 0;
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }       
        
        }

        public void request_download(int seg_no)
        {
            byte[] temp_data;
            temp_data = BitConverter.GetBytes(flashAddr[seg_no]);

            CanMessageOut.DATA[0] = 0x10;       //  request download
            CanMessageOut.DATA[1] = 0x0A;       //  start address
            CanMessageOut.DATA[2] = 0x34;
            CanMessageOut.DATA[3] = temp_data[0];
            CanMessageOut.DATA[4] = temp_data[1];
            CanMessageOut.DATA[5] = temp_data[2];
            CanMessageOut.DATA[6] = temp_data[3];               
            CanMessageOut.DATA[7] = 0x00; // invalid data
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x00)
                ReturnValue = 0;
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }   
            Thread.Sleep(FLASH_CMD_DLY);

            temp_data = BitConverter.GetBytes(FileSize[seg_no]);

            CanMessageOut.DATA[0] = 0x21;       //  request download
            CanMessageOut.DATA[1] = temp_data[0];       //  length
            CanMessageOut.DATA[2] = temp_data[1];
            CanMessageOut.DATA[3] = temp_data[2];
            CanMessageOut.DATA[4] = temp_data[3];
            CanMessageOut.DATA[5] = 0x00;
            CanMessageOut.DATA[6] = 0x00;
            CanMessageOut.DATA[7] = 0x00;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x74)
                ReturnValue = 0;
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }   
            BLOCK_SIZE = (int)CanMessageIn.DATA[2];
            BLOCK_SIZE |= ((int)CanMessageIn.DATA[3]) << 8;
        }

        public void delete_flash(int seg_no)
        {
            byte[] temp_data;
            temp_data = BitConverter.GetBytes(flashAddr[seg_no]);

            CanMessageOut.DATA[0] = 0x10;       //  delete flash
            CanMessageOut.DATA[1] = 0x0a;   //  
            CanMessageOut.DATA[2] = 0x31;
            CanMessageOut.DATA[3] = 0x02;
            CanMessageOut.DATA[4] = temp_data[0];
            CanMessageOut.DATA[5] = temp_data[1];
            CanMessageOut.DATA[6] = temp_data[2];
            CanMessageOut.DATA[7] = temp_data[3];
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x00)
                ReturnValue = 0;
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
            Thread.Sleep(FLASH_CMD_DLY);
            
            
            temp_data = BitConverter.GetBytes(FileSize[seg_no]);

            CanMessageOut.DATA[0] = 0x21;               //  deleted flash
            CanMessageOut.DATA[1] = temp_data[0];       //  length
            CanMessageOut.DATA[2] = temp_data[1];
            CanMessageOut.DATA[3] = temp_data[2];
            CanMessageOut.DATA[4] = temp_data[3];
            CanMessageOut.DATA[5] = 0x00;
            CanMessageOut.DATA[6] = 0x00;
            CanMessageOut.DATA[7] = 0x00;      
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);


            MessageOk = false;
            ReadCount = WAIT_TIME;
            CanMessageIn.DATA[1] = 0x00;
            ReturnValue = 0;

            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                
                if(ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    return;
                    //SendMessageEndEvent(OpArgs);
                }
                if(MessageOk == true)
                    {
                    ReadCount = WAIT_TIME/4;
                    }
            } while (CanMessageIn.DATA[1] != 0x71);
            
            if (CanMessageIn.DATA[1] == 0x71)
                ReturnValue = 0;
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }       
        }

        public void calculate_checksum(int seg_no)
        {
            byte[] temp_data;

            temp_data = BitConverter.GetBytes(flashAddr[seg_no]);           
            CanMessageOut.DATA[0] = 0x10;   //  calculate checksum
            CanMessageOut.DATA[1] = 0x0C;   // 
            CanMessageOut.DATA[2] = 0x31;
            CanMessageOut.DATA[3] = 0x03;
            CanMessageOut.DATA[4] = temp_data[0];
            CanMessageOut.DATA[5] = temp_data[1];
            CanMessageOut.DATA[6] = temp_data[2];
            CanMessageOut.DATA[7] = temp_data[3];

            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x00)
                ReturnValue = 0;
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
            Thread.Sleep(FLASH_CMD_DLY);


            temp_data = BitConverter.GetBytes(FileSize[seg_no] - 1 + flashAddr[seg_no]);                

            CanMessageOut.DATA[0] = 0x21;   //  Sequence Counter
            CanMessageOut.DATA[1] = temp_data[0];   //  7 bytes of Data
            CanMessageOut.DATA[2] = temp_data[1];

            
            CanMessageOut.DATA[3] = temp_data[2];
            CanMessageOut.DATA[4] = temp_data[3];

            temp_data = BitConverter.GetBytes(flash_checksum[seg_no]);              
            
            CanMessageOut.DATA[5] = temp_data[0];
            CanMessageOut.DATA[6] = temp_data[1];
            CanMessageOut.DATA[7] = 0x00;

            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x71)
            {
                ReturnValue = 0;
            }
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }       
        }

        public void request_transfer_exit(int seg_no)
        {
            byte[] temp_data;

            temp_data = BitConverter.GetBytes(flashAddr[seg_no]);           


            
            CanMessageOut.DATA[0] = 0x10;   //  Request flash exit
            CanMessageOut.DATA[1] = 0x0A;   // 
            CanMessageOut.DATA[2] = 0x37;

            
            CanMessageOut.DATA[3] = temp_data[0];
            CanMessageOut.DATA[4] = temp_data[1];
            CanMessageOut.DATA[5] = temp_data[2];
            CanMessageOut.DATA[6] = temp_data[3];
            CanMessageOut.DATA[7] = 0x00;

            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
        
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    //SendFlashEndEvent(Args);
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x00)
                ReturnValue = 0;
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
            Thread.Sleep(FLASH_CMD_DLY);
            

            temp_data = BitConverter.GetBytes(FileSize[seg_no]);                

            CanMessageOut.DATA[0] = 0x21;   //  Sequence Counter
            CanMessageOut.DATA[1] = temp_data[0];   //  7 bytes of Data
            CanMessageOut.DATA[2] = temp_data[1];

            
            CanMessageOut.DATA[3] = temp_data[2];
            CanMessageOut.DATA[4] = temp_data[3];
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;

            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);


            MessageOk = false;
            ReadCount = WAIT_TIME;
        
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x77)
                ReturnValue = 0;
            else
            {
                ReturnValue = -99;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }   
        
        }
        public void ecu_reset()
        {
            CanMessageOut.ID = KWP_SEND_ALL;
            CanMessageOut.DATA[0] = 2;      //  start default session
            CanMessageOut.DATA[1] = 0x11;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x01;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x51)
                ReturnValue = 0;
            else
            {
                ReturnValue = 0;
                OpArgs.ReturnOpValue = ReturnValue;
                SendMessageEndEvent(OpArgs);
            }
            CanMessageOut.ID = TxNodeId;
        }

        public uint secacc_crypto_56( uint seed )
        {
           uint rv;
           Byte[] data;
           Byte[] data1;

           data = new byte[4];
           data1 = new byte[4];

           data1 = BitConverter.GetBytes(seed);

            

           data[3] = data1[0];

           data[2] = data1[1];

           data[1] = data1[2];

           data[0] = data1[3];

           data[0] += 0x97;
           data[1] += 0x28;
           data[2] += 0xAA;
           data[3] += 0x55;

           rv = data[3];
           rv <<= 8;
           rv |= data[2];
           rv <<= 8;
           rv |= data[1];
           rv <<= 8;
           rv |= data[0];

           return rv;
        }

        public void ReadSerialNumber()
        {
            CanMessageOut.DATA[0] = 2;          //  start default session
            CanMessageOut.DATA[1] = 0x1A;   //  7 bytes of Data
            CanMessageOut.DATA[2] = 0x88;
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    break;
                }

            } while (MessageOk == false); 

            if (CanMessageIn.DATA[1] == 0x5A)
            {
                byte[] byte_array = new byte[] { CanMessageIn.DATA[2], CanMessageIn.DATA[3], CanMessageIn.DATA[4], CanMessageIn.DATA[5], CanMessageIn.DATA[6], CanMessageIn.DATA[7] };

                serial_number = System.Text.Encoding.ASCII.GetString(byte_array).PadLeft(8, '0');
                SendKwpEvent(Args);

                byte[] bytes = Encoding.UTF8.GetBytes(serial_number.ToUpper()+secu_secret+mac_address.ToUpper());
                byte[] hash = SHA256Managed.Create().ComputeHash(bytes);
                string local_key = "";
                for (int i = 0; i < 4; i++)
                {
                    local_key += (hash[hash.Length - 4 + i].ToString("X2"));
                }

                if(local_key.ToUpper() == security_key)
                {
                    ReturnValue = 0;   
                }
                else
                {
                    ReturnValue = -99;
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }

            }
        }

        public class MessageOpArgs : EventArgs
        {
            public int ReturnOpValue;

        }


        public void ProcessKWP()
        {
            byte[] id_byte;
            id_byte = new byte[4];
            id_byte = BitConverter.GetBytes(kwp_object);


            CanMessageOut.LEN = 8;
            CanMessageOut.ID = TxNodeId;
            CanMessageOut.MSGTYPE = 0;
            
            CanMessageOut.DATA[0] = 2;          //  start default session
            CanMessageOut.DATA[1] = id_byte[2]; //  7 bytes of Data
            CanMessageOut.DATA[2] = id_byte[0];
            CanMessageOut.DATA[3] = 0xff;
            CanMessageOut.DATA[4] = 0xff;
            CanMessageOut.DATA[5] = 0xff;
            CanMessageOut.DATA[6] = 0xff;
            CanMessageOut.DATA[7] = 0xff;
            MessageToSend.ConvertNewMessage(CanMessageOut);
            SendFlashMessage(MessageToSend);

            MessageOk = false;
            ReadCount = WAIT_TIME;
        
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, RxNodeId);
                if (ReadCount-- == 0)
                {
                    break;
                }

            } while (MessageOk == false);
            
            if (CanMessageIn.DATA[1] == 0x5A)
            {
                byte[] byte_array = new byte[] { CanMessageIn.DATA[2], CanMessageIn.DATA[3], CanMessageIn.DATA[4], CanMessageIn.DATA[5], CanMessageIn.DATA[6], CanMessageIn.DATA[7] };

                serial_number = System.Text.Encoding.ASCII.GetString(byte_array).PadLeft(8, '0');
                SendKwpEvent(Args);
            }
        }
        
        //public int GetBlockCount(string FileInName, int NodeId)
        public void GetBlockCount()
        {
            byte[] write_value;
            write_value = new byte[4];
                      
            FlashOpOn = true;

            SDOVarInit();

            InitSegData();

            /**********  Transfer Control to Application ******************/
            CanMessageOut.LEN = 8;
            CanMessageOut.ID = TxNodeId;
            CanMessageOut.MSGTYPE = 0;

            start_diagnostic();
            Thread.Sleep(FLASH_CMD_DLY);
            ReadSerialNumber();
            Thread.Sleep(FLASH_CMD_DLY);
            read_hw_id();
            Thread.Sleep(FLASH_CMD_DLY);
            read_software_version();
            Thread.Sleep(FLASH_CMD_DLY);
            read_partnumber();
            Thread.Sleep(FLASH_CMD_DLY);
            read_swid();
            Thread.Sleep(FLASH_CMD_DLY);
            secacc_process_34();
            Thread.Sleep(FLASH_CMD_DLY);
            enter_passive_mode();
            Thread.Sleep(3000);
            
            write_value[0] = 0;
            write_value[0] = 0;
            write_value[0] = 0; 
            write_value[0] = 0;     
            
            write_param(00, write_value, 6);
            Thread.Sleep(2000);
            start_flasher();
            Thread.Sleep(2000); // wait reset
            secacc_process_12();
            Thread.Sleep(120);
            start_programming();
            Thread.Sleep(FLASH_CMD_DLY);
            delete_flash(7); //deleted last one

            for(int i = 0; i < 8; i++)
            {
                flash_data(i);
            }
            Thread.Sleep(FLASH_CMD_DLY);
            stop_diagnostic();
            Thread.Sleep(FLASH_CMD_DLY);
            ecu_reset();
            ReturnValue = 0;
            Thread.Sleep(4000);
            read_software_version();
            Thread.Sleep(FLASH_CMD_DLY);
            read_swid();            
            Thread.Sleep(FLASH_CMD_DLY);
            read_swid2();
            
            Thread.Sleep(FLASH_CMD_DLY);
            read_swid3();
            Thread.Sleep(FLASH_CMD_DLY);
            read_brandid();
            Thread.Sleep(FLASH_CMD_DLY);
            read_ecu_variant();
            Thread.Sleep(FLASH_CMD_DLY);
            read_partnumber();
            Thread.Sleep(FLASH_CMD_DLY);
            secacc_process_34();
            Thread.Sleep(FLASH_CMD_DLY);
            enter_passive_mode();
            Thread.Sleep(FLASH_CMD_DLY);
            secacc_process_56();
            Thread.Sleep(FLASH_CMD_DLY);

            write_value[0] = 0x00;
            write_value[1] = 0x01;

            write_param(3, write_value, 4);
            Thread.Sleep(FLASH_CMD_DLY);

            write_value[0] = 0x19;
            write_value[1] = 0x00;

            write_param(0x80, write_value, 4);
            Thread.Sleep(FLASH_CMD_DLY);

            write_value[0] = 0x86;
            write_value[1] = 0x0B;

            write_param(0x36, write_value, 4);  
            Thread.Sleep(FLASH_CMD_DLY);

            write_value[0] = 0x01;
            write_value[1] = 0x00;

            write_param(0x20, write_value, 4);  
            Thread.Sleep(FLASH_CMD_DLY);

            write_value[0] = 0x01;
            write_value[1] = 0x00;

            write_param(0xc0, write_value, 4);
            Thread.Sleep(FLASH_CMD_DLY);
            seacc_ff();
            Thread.Sleep(FLASH_CMD_DLY);
            secacc_process_34();
            Thread.Sleep(500);
            start_flasher();
            Thread.Sleep(2000);
            secacc_process_12();
            Thread.Sleep(100);
            start_programming();
            Thread.Sleep(100);
            ecu_reset();
            Thread.Sleep(4000);

            verify_brandid();
            Thread.Sleep(FLASH_CMD_DLY);
            verify_ecu_variant();
            Thread.Sleep(FLASH_CMD_DLY);
            verify_ID36();
            Thread.Sleep(FLASH_CMD_DLY);
            verify_ID20();  
            Thread.Sleep(FLASH_CMD_DLY);
            verify_IDC0();
            Thread.Sleep(FLASH_CMD_DLY);
            read_partnumber();
            Thread.Sleep(FLASH_CMD_DLY);       
            secacc_process_34();
            Thread.Sleep(100);
            enter_passive_mode();
            Thread.Sleep(100);
            
            write_value[0] = 0x08;   // write partnumber
            write_value[1] = 0x04;
            write_value[2] = 0xDE;
            write_value[3] = 0x44;          

            write_param(0x00, write_value, 6);
            start_flasher();
            Thread.Sleep(2000);
            secacc_process_12();
            Thread.Sleep(100);
            start_programming();
            Thread.Sleep(100);
            ecu_reset();
            Thread.Sleep(4000);
            verify_partnumber();
            Thread.Sleep(FLASH_CMD_DLY);


            FileOpen = false;
            FlashOpOn = false;
            
            OpArgs.ReturnOpValue = ReturnValue;
            SendMessageEndEvent(OpArgs); 

        }



        private int EndBlockDownload(int NodeId)
        {

            //626  110nnn01 00 00 00 00 00 00 00    //SDO MOSI, Node ID=0x26, Block Upload Transfer disconnect from client, Number of bytes not valid in previous segment=nnn(usually just = 0)
            for (int i = 0; i < 7; i++)
                Fragment[i] = 0;                    // flush transmit buffer

            CanMessageOut.DATA[0] = 0xC1;   //  End Block Download
            CanMessageOut.DATA[1] = 0x00;   //  7 bytes of Data (all = 0)
            CanMessageOut.DATA[2] = 0x00;
            CanMessageOut.DATA[3] = 0x00;
            CanMessageOut.DATA[4] = 0x00;
            CanMessageOut.DATA[5] = 0x00;
            CanMessageOut.DATA[6] = 0x00;
            CanMessageOut.DATA[7] = 0x00;

            MessageToSend.ConvertNewMessage(CanMessageOut);
            //SendCanMessage(ref MessageToSend);
            SendFlashMessage(MessageToSend);

            //Thread.Sleep(1);

            //526  A1 00 00 00 00 00 00 00      //SDO MISO, Node ID=0x26, Block Upload Transfer disconnect from server

            MessageOk = false;
            ReadCount = WAIT_TIME;
            do
            {
                MessageOk = ReadCANMessage(ref CanMessageIn, 0x580);
                if (ReadCount-- == 0)
                    return -99;

            } while (MessageOk == false);

            if (CanMessageIn.DATA[0] == 0xA1)
                return 0;
            else
            {
                return -99;
            }        
        }



        public void CANValueTransfer()
        {
            if (ValueWrite)
                OpArgs.ReturnOpValue = SendSDOWrite();
            else
                OpArgs.ReturnOpValue = SendSDORead();
            FlashOpOn = false;
            //SendFlashEndEvent(Args);
            SendMessageEndEvent(OpArgs);

        }



        public void DeviseProfileThread()
        {

            
            while (!LastValue)
            {
                if (SendValue)
                {
                    if (SendMessageON)
                    {
                        if (SegmentTransferON)
                        {
                            if (SegmentWrite)
                                OpArgs.ReturnOpValue = (int) Segment_Transfer_Write(CommandObjectIndex, StringIn, NodeId);
                            else
                                OpArgs.ReturnOpValue = (int) Segment_Transfer_Read(CommandObjectIndex, StringData, NodeId);
                        }
                        else
                        {

                            if (ValueWrite)
                                OpArgs.ReturnOpValue = SendSDOWrite();
                            else
                                OpArgs.ReturnOpValue = SendSDORead();
                        }
                    }
                    
                    //if ((SetLastValue) || (ReturnValue != 0))
                    if (SetLastValue)
                        LastValue = true;
                    SendValue = false;
                    //SendFlashEndEvent(Args);
                    SendMessageEndEvent(OpArgs);
                    
                }
            }

        }




        public int SendSDORead()
        {
            int DataIn;
            
            FlashOpOn = true;
            SDOVarInit();
            SDODataValue = 0;
            ReturnValue = 0;

            CanMessageOut.LEN = 8;
            CanMessageOut.ID = 0x600 + (uint)NodeId;
            CanMessageOut.MSGTYPE = 0;



            if (CommandObjectIndex != 0)
            {

                CanMessageOut.DATA[0] = ClientCommandSpecifier;                             //  CS_Byte
                CanMessageOut.DATA[1] = (byte)((CommandObjectIndex & 0x0000FF00) >> 8);     // LSByte of Index
                CanMessageOut.DATA[2] = (byte)((CommandObjectIndex & 0x00FF0000) >> 16);    // MSByte of Index
                CanMessageOut.DATA[3] = (byte)(CommandObjectIndex & 0x000000FF);            // SubIndex
                CanMessageOut.DATA[4] = (byte)((SDODataValue & 0x000000FF));                //  LSByte of LSWord
                CanMessageOut.DATA[5] = (byte)((SDODataValue & 0x0000FF00) >> 8);           //  MSByte of LSWord
                CanMessageOut.DATA[6] = (byte)((SDODataValue & 0x00FF0000) >> 16);          //  LSByte of MSWord
                CanMessageOut.DATA[7] = (byte)((SDODataValue & 0xFF000000) >> 24);          //  MSByte of MSWord


                MessageToSend.ConvertNewMessage(CanMessageOut);
                SendFlashMessage(MessageToSend);

                //Receive 5XX  60 AA AA BB CC CC CC CC  SDO MISO, Node ID=0xXX
                MessageOk = false;
                ReadCount = WAIT_TIME;

                do
                {
                    MessageOk = ReadCANMessage(ref CanMessageIn, 0x580);
                    if (ReadCount-- == 0)
                    {
                        //SendFlashEndEvent(Args);
                        ReturnValue = -99;
                        OpArgs.ReturnOpValue = ReturnValue;
                        SendMessageEndEvent(OpArgs);
                    }

                } while (MessageOk == false);

                //if (CanMessageIn.Data[0] == 0x60)
                //    ReturnValue = 1;
                //else
                //{
                //    ReturnValue = -99;
                //    SendFlashEndEvent(Args);
                //}

                if (CanMessageIn.DATA[0] == 0x80)
                {
                    ReturnValue = -99;
                    //SendFlashEndEvent(Args);
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);
                }
                DataIn = CanMessageIn.DATA[4] + (CanMessageIn.DATA[5] << 8) + (CanMessageIn.DATA[6] << 16) + (CanMessageIn.DATA[7] << 24);
                StringData1 = DataIn.ToString("X");

            }
            else
                ReturnValue = -99;

            return ReturnValue;
        }



        public int SendSDOWrite()
        {
            int DataIn;

            ReturnValue = 0;
            FlashOpOn = true;
            SDOVarInit();


            CanMessageOut.LEN = 8;
            CanMessageOut.ID = 0x600 + (uint)NodeId;
            CanMessageOut.MSGTYPE = 0;



            if (CommandObjectIndex != 0)
            {

                CanMessageOut.DATA[0] = ClientCommandSpecifier;                             //  CS_Byte
                CanMessageOut.DATA[1] = (byte)((CommandObjectIndex & 0x0000FF00) >> 8);     // LSByte of Index
                CanMessageOut.DATA[2] = (byte)((CommandObjectIndex & 0x00FF0000) >> 16);    // MSByte of Index
                CanMessageOut.DATA[3] = (byte)(CommandObjectIndex & 0x000000FF);            // SubIndex
                CanMessageOut.DATA[4] = (byte)((SDODataValue & 0x000000FF));                //  LSByte of LSWord
                CanMessageOut.DATA[5] = (byte)((SDODataValue & 0x0000FF00) >> 8);           //  MSByte of LSWord
                CanMessageOut.DATA[6] = (byte)((SDODataValue & 0x00FF0000) >> 16);          //  LSByte of MSWord
                CanMessageOut.DATA[7] = (byte)((SDODataValue & 0xFF000000) >> 24);          //  MSByte of MSWord


                MessageToSend.ConvertNewMessage(CanMessageOut);
                SendFlashMessage(MessageToSend); 

                //Receive 5XX  60 AA AA BB CC CC CC CC  SDO MISO, Node ID=0xXX
                MessageOk = false;
                ReadCount = WAIT_TIME;

                do
                {
                    MessageOk = ReadCANMessage(ref CanMessageIn, 0x580);
                    if (ReadCount-- == 0)
                    {
                        //SendFlashEndEvent(Args);
                        ReturnValue = -99;
                        OpArgs.ReturnOpValue = ReturnValue;
                        SendMessageEndEvent(OpArgs);
                    }

                } while (MessageOk == false);


                if (CanMessageIn.DATA[0] == 0x80)
                {
                    ReturnValue = -99;
                    OpArgs.ReturnOpValue = ReturnValue;
                    SendMessageEndEvent(OpArgs);

                }

                DataIn = CanMessageIn.DATA[4] + (CanMessageIn.DATA[5] << 8) + (CanMessageIn.DATA[6] << 16) + (CanMessageIn.DATA[7] << 24);
                StringData1 = DataIn.ToString("X");

            }
            else
                ReturnValue = -1;

            return ReturnValue;

        }

        public void ClearEvents()
        {
            if (FlashOpDone != null)
            {
                foreach (MessageOpHandler eventDelegate in FlashOpDone.GetInvocationList())
                    FlashOpDone -= eventDelegate;
            }
        }
        
        
        protected virtual void SendMessageEndEvent(MessageOpArgs e)
        {

            if (FileOpen)
            {
                FileOpen = false;
            }
            if (MessageOpDone != null)
                MessageOpDone(this, e);
            if (FlashOpDone != null)
                FlashOpDone(this, e);
        }
        
        protected virtual void SendTickEvent(EventArgs e)
        {

            if (TickDone != null)
                TickDone(this, e);
        }

        protected virtual void SendKwpEvent(EventArgs e)
        {

            if (KwpDone != null)
                OSKwpDone(this, e);
        }       

        private void AddRXMessage(TPCANMsg MessageIn)
        {
            MsgQueue.Enqueue(MessageIn);
            if((this.CANMsgRxEvent != null) && (data_download == 0))
            {
                //CANMsgRxEvent(ref MessageIn, true);   
            }
            
        }

        
        
        private bool ReadCANMessage(ref TPCANMsg MessageIn, uint MessageType)
        {
            bool MessageFound = false;

            if (MsgQueue.Count > 0)
            {
                MessageIn = MsgQueue.Dequeue();
                if (MessageIn.ID == MessageType)
                {
                    MessageFound = true;
                    if((this.CANMsgRxEvent != null) && (data_download < 2))
                    {
                        CANMsgRxEvent(ref MessageIn, true); 
                    }                   
                }
            }
            return MessageFound;
        }

        private void SDOVarInit()
        {
            MsgQueue.Clear();
            StringData1 = "";
        }


        private void SDOVarClear()
        {
            MsgQueue.Clear();
        
        }
    }
}
